<template>
  <div class="certificate-template">
    <div class="template-header">
      <div class="header-left">
        <el-button @click="$router.push('/main')" type="default">
          <el-icon><arrow-left /></el-icon>
          返回
        </el-button>
        <h2>创建证书模板</h2>
        <el-input
          v-model="templateName"
          placeholder="请输入模板名称"
          class="template-name-input"
          clearable
        >
          <template #prepend>模板名称</template>
        </el-input>
      </div>
      <div class="actions">
        <el-button type="primary" @click="saveTemplate">保存模板</el-button>
        <el-button @click="previewTemplate">预览</el-button>
      </div>
    </div>

    <div class="template-content">
      <div class="tools-panel">
        <h3>添加字段</h3>
        <div class="field-list">
          <div
            v-for="field in availableFields"
            :key="field.type"
            class="field-item"
            draggable="true"
            @dragstart="onDragStart($event, field)"
          >
            {{ field.label }}
          </div>
        </div>
        <div class="template-upload">
          <h3>上传模板背景</h3>
          <el-upload
            class="upload-demo"
            drag
            action="#"
            :auto-upload="false"
            :show-file-list="false"
            accept="application/pdf"
            :on-change="handleFileChange"
          >
            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
            <div class="el-upload__text">
              拖拽PDF文件到此处或 <em>点击上传</em>
            </div>
            <template #tip>
              <div class="el-upload__tip">
                只支持 PDF 格式文件
              </div>
            </template>
          </el-upload>
        </div>
      </div>

      <div class="design-area">
        <div 
          v-if="pdfUrl"
          class="template-background"
          @dragover.prevent
          @drop="onDrop"
        >
          <canvas ref="pdfCanvas" class="pdf-canvas"></canvas>
          <div
            v-for="(field, index) in placedFields"
            :key="index"
            class="placed-field"
            :style="getEditFieldStyle(field)"
            draggable="true"
            @dragstart="onPlacedFieldDragStart($event, index)"
            @click="selectField(index)"
          >
            {{ field.previewText }}
          </div>
        </div>
        <div v-else class="empty-background">
          请先上传PDF证书模板
        </div>
      </div>

      <div class="properties-panel" v-if="selectedFieldIndex !== null">
        <h3>字段属性</h3>
        <div class="property-item">
          <label>字体大小</label>
          <el-input-number 
            v-model="placedFields[selectedFieldIndex].fontSize" 
            :min="12" 
            :max="72"
            @change="updateField"
          />
        </div>
        <div class="property-item">
          <label>字体颜色</label>
          <el-color-picker 
            v-model="placedFields[selectedFieldIndex].color"
            @change="updateField"
          />
        </div>
        <div class="property-item">
          <label>字体粗细</label>
          <el-select 
            v-model="placedFields[selectedFieldIndex].fontWeight"
            @change="updateField"
          >
            <el-option label="正常" value="normal" />
            <el-option label="粗体" value="bold" />
          </el-select>
        </div>
        <el-button type="danger" @click="deleteField">删除字段</el-button>
      </div>
    </div>

    <!-- 预览对话框 -->
    <el-dialog
      v-model="previewVisible"
      title="证书模板预览"
      width="80%"
      :close-on-click-modal="false"
    >
      <div class="preview-container">
        <div class="preview-background">
          <canvas ref="previewCanvas" class="pdf-canvas"></canvas>
          <div
            v-for="(field, index) in placedFields"
            :key="index"
            class="preview-field"
            :style="getPreviewFieldStyle(field)"
          >
            {{ field.previewText }}
          </div>
        </div>
      </div>
    </el-dialog>

    <!-- 快捷键提示卡片 -->
    <el-card class="shortcut-tips">
      <template #header>
        <div class="tips-header">
          <el-icon><Operation /></el-icon>
          <span>快捷键提示</span>
        </div>
      </template>
      <div class="tips-content">
        <div class="tip-item">
          <span class="key">↑↓←→</span>
          <span class="description">正常调整位置</span>
        </div>
        <div class="tip-item">
          <span class="key">Shift + ↑↓←→</span>
          <span class="description">精细调整位置</span>
        </div>
        <div class="tip-item">
          <span class="key">Ctrl + ↑↓←→</span>
          <span class="description">大幅调整位置</span>
        </div>
      </div>
    </el-card>
  </div>
</template>

<script setup>
import { ref, onMounted, watch, nextTick, onUnmounted } from 'vue'
import { UploadFilled, ArrowLeft, Operation } from '@element-plus/icons-vue'
import { ElMessage, ElLoading } from 'element-plus'
import * as pdfjsLib from 'pdfjs-dist'
import axios from 'axios'
import request from '../../utils/request'
import { previewCertificateTemplate } from '../../api/dashboard'

// 设置PDF.js worker
pdfjsLib.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib.version}/build/pdf.worker.min.js`

// 可用字段列表
const availableFields = ref([
  { type: 'name', label: '姓名', previewText: '张三', fieldKey: 'studentName' },
  { type: 'content', label: '正文', previewText: '兹证明该同学已完成所有课程考试...', fieldKey: 'content' },
  { type: 'organization', label: '颁发机构', previewText: 'XX教育机构', fieldKey: 'organization' },
  { type: 'date', label: '颁发时间', previewText: '2024年3月15日', fieldKey: 'issueDate' },
  { type: 'code', label: '证书编码', previewText: 'CERT-2024-001', fieldKey: 'certificateCode' }
])

// PDF URL
const pdfUrl = ref('')
const pdfData = ref(null)
const pdfCanvas = ref(null)
const previewCanvas = ref(null)
const placedFields = ref([])
const selectedFieldIndex = ref(null)
const previewVisible = ref(false)

// PDF原始尺寸
const pdfOriginalWidth = ref(0)
const pdfOriginalHeight = ref(0)

// 微调步长
const BASE_NUDGE_STEP = 0.005 // 基础步长
const FINE_NUDGE_STEP = 0.001 // 精细步长（按住Shift）
const LARGE_NUDGE_STEP = 0.01 // 大步长（按住Ctrl）

// 新增模板名称、背景路径等数据
const templateName = ref('')
const backgroundPath = ref('') // 你实际上传背景后应赋值

// 处理PDF文件上传
const handleFileChange = async (file) => {
  if (file.raw.type !== 'application/pdf') {
    ElMessage.error('只支持PDF格式文件！')
    return false
  }

  try {
    const reader = new FileReader()
    reader.onload = async (e) => {
      const arrayBuffer = e.target.result
      // Create a copy of the ArrayBuffer to prevent detachment
      pdfData.value = arrayBuffer.slice(0)
      pdfUrl.value = URL.createObjectURL(file.raw)
      // 等待DOM更新后再渲染PDF
      await nextTick()
      await renderPDF(arrayBuffer.slice(0), pdfCanvas.value)
    }
    reader.onerror = () => {
      ElMessage.error('PDF文件读取失败，请重试！')
    }
    reader.readAsArrayBuffer(file.raw)
  } catch (error) {
    console.error('处理PDF文件失败:', error)
    ElMessage.error('处理PDF文件失败，请重试')
  }
}

// 渲染PDF
const renderPDF = async (data, canvas) => {
  if (!canvas) {
    console.error('Canvas element not found')
    return
  }

  try {
    console.log('[renderPDF] 开始渲染PDF, 数据长度:', data.byteLength)
    const dataCopy = data.slice(0)
    const loadingTask = pdfjsLib.getDocument({ data: dataCopy })
    const pdf = await loadingTask.promise
    console.log('[renderPDF] PDF加载成功, 页数:', pdf.numPages)
    const page = await pdf.getPage(1) // 获取第一页
    console.log('[renderPDF] 获取第一页成功')
    // 获取viewport
    const viewport = page.getViewport({ scale: 1.0 })
    pdfOriginalWidth.value = viewport.width
    pdfOriginalHeight.value = viewport.height
    console.log('[前端PDF原始尺寸] width:', viewport.width, 'height:', viewport.height)
    // 获取canvas的容器尺寸
    const container = canvas.parentElement
    const containerWidth = container.clientWidth
    const containerHeight = container.clientHeight
    console.log('[renderPDF] 容器尺寸:', containerWidth, containerHeight)
    // 计算适当的缩放比例
    const scaleX = containerWidth / viewport.width
    const scaleY = containerHeight / viewport.height
    const scale = Math.min(scaleX, scaleY)
    console.log('[renderPDF] 计算缩放比例:', scale)
    // 使用计算出的缩放比例创建新的viewport
    const scaledViewport = page.getViewport({ scale })
    console.log('[renderPDF] 缩放后的视口尺寸:', scaledViewport.width, scaledViewport.height)
    // 设置canvas尺寸
    canvas.width = scaledViewport.width
    canvas.height = scaledViewport.height
    console.log('[renderPDF] 设置canvas尺寸:', canvas.width, canvas.height)
    // 渲染PDF
    const context = canvas.getContext('2d')
    console.log('[renderPDF] 开始渲染到canvas')
    await page.render({
      canvasContext: context,
      viewport: scaledViewport
    }).promise
    console.log('[renderPDF] 渲染完成')
  } catch (error) {
    console.error('渲染PDF失败:', error)
    // 显示错误信息
    if (canvas) {
      const context = canvas.getContext('2d')
      if (context) {
        context.fillStyle = '#f5f7fa'
        context.fillRect(0, 0, canvas.width, canvas.height)
        context.fillStyle = '#f56c6c'
        context.font = '14px Arial'
        context.textAlign = 'center'
        context.fillText('PDF渲染失败: ' + (error.message || '未知错误'), canvas.width / 2, canvas.height / 2)
      }
    }
  }
}

// 开始拖动字段
const onDragStart = (event, field) => {
  event.dataTransfer.setData('field', JSON.stringify({
    ...field,
    fontSize: 16,
    color: '#000000',
    fontWeight: 'normal',
    previewText: field.previewText
  }))
}

// 开始拖动已放置的字段
const onPlacedFieldDragStart = (event, index) => {
  event.dataTransfer.setData('placedFieldIndex', index.toString())
}

// 放置字段
const onDrop = async (event) => {
  const placedFieldIndex = event.dataTransfer.getData('placedFieldIndex')
  const canvas = pdfCanvas.value
  const rect = canvas.getBoundingClientRect()
  const scaleX = pdfOriginalWidth.value / rect.width
  const scaleY = pdfOriginalHeight.value / rect.height
  const canvasX = event.offsetX
  const canvasY = event.offsetY
  const pdfX = canvasX * scaleX
  const pdfY = canvasY * scaleY
  const percentX = pdfX / pdfOriginalWidth.value
  const percentY = pdfY / pdfOriginalHeight.value
  if (placedFieldIndex !== '') {
    const index = parseInt(placedFieldIndex)
    placedFields.value[index].percentX = percentX
    placedFields.value[index].percentY = percentY
    console.log('[字段拖放] label:', placedFields.value[index].label, 'canvasX:', canvasX, 'canvasY:', canvasY, 'pdfX:', pdfX, 'pdfY:', pdfY, 'percentX:', percentX, 'percentY:', percentY, 'fontSize:', placedFields.value[index].fontSize, 'color:', placedFields.value[index].color, 'fontWeight:', placedFields.value[index].fontWeight)
  } else {
    try {
      const fieldData = JSON.parse(event.dataTransfer.getData('field'))
      placedFields.value.push({
        ...fieldData,
        percentX,
        percentY,
        fontSize: fieldData.fontSize || 16,
        color: fieldData.color || '#000000',
        fontWeight: fieldData.fontWeight || 'normal'
      })
      console.log('[字段拖放] label:', fieldData.label, 'canvasX:', canvasX, 'canvasY:', canvasY, 'pdfX:', pdfX, 'pdfY:', pdfY, 'percentX:', percentX, 'percentY:', percentY, 'fontSize:', fieldData.fontSize, 'color:', fieldData.color, 'fontWeight:', fieldData.fontWeight)
    } catch (error) {
      console.error('字段数据解析失败:', error)
    }
  }
}

// 选择字段
const selectField = (index) => {
  selectedFieldIndex.value = index
}

// 更新字段属性
const updateField = async () => {
  // 保证所有字段都带有 percentX/percentY
  placedFields.value = placedFields.value.map(f => ({
    ...f,
    percentX: f.percentX ?? 0.5,
    percentY: f.percentY ?? 0.5
  }))
  
  // 不需要修正位置，因为我们使用transform: translate(-50%, -50%)居中显示
  console.log('[更新字段属性] 完成');
}

// 删除字段
const deleteField = () => {
  if (selectedFieldIndex.value !== null) {
    placedFields.value.splice(selectedFieldIndex.value, 1)
    selectedFieldIndex.value = null
  }
}

// 保存模板
const saveTemplate = async () => {
  if (!templateName.value.trim()) {
    ElMessage.warning('请输入模板名称')
    return
  }
  if (!pdfData.value) {
    ElMessage.warning('请先上传PDF证书模板')
    return
  }
  if (placedFields.value.length === 0) {
    ElMessage.warning('请至少添加一个字段')
    return
  }

  // 从本地存储获取用户信息
  const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}')
  if (!userInfo.username) {
    ElMessage.error('未获取到用户信息，请重新登录')
    return
  }

  const templateData = {
    templateName: templateName.value.trim(),
    pdfBase64: pdfData.value ? arrayBufferToBase64(pdfData.value) : null,
    backgroundPath: backgroundPath.value || '',
    fields: placedFields.value,
    creatorId: userInfo.username // 使用userInfo中的username作为creatorId
  }

  try {
    const loading = ElLoading.service({
      lock: true,
      text: '保存模板中...',
      background: 'rgba(255, 255, 255, 0.7)'
    })

    await request.post('/dashboard/certificate/template/save', templateData)
    ElMessage.success('模板保存成功')
    loading.close()
  } catch (error) {
    console.error('保存模板失败:', error)
    ElMessage.error('模板保存失败：' + (error.message || '未知错误'))
  }
}

// ArrayBuffer转Base64
const arrayBufferToBase64 = (buffer) => {
  let binary = '';
  const bytes = new Uint8Array(buffer);
  const len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}

// Base64转ArrayBuffer
const base64ToArrayBuffer = (base64) => {
  const binaryString = window.atob(base64);
  const len = binaryString.length;
  const bytes = new Uint8Array(len);
  for (let i = 0; i < len; i++) {
    bytes[i] = binaryString.charCodeAt(i);
  }
  return bytes.buffer;
}

// 预览模板
const previewTemplate = async () => {
  if (!pdfData.value) {
    ElMessage.warning('请先上传PDF模板')
    return
  }

  try {
    previewVisible.value = true
    await nextTick()
    // 使用相同的PDF数据渲染到预览canvas
    await renderPDF(pdfData.value.slice(0), previewCanvas.value)
    // 等待渲染完成后再次触发更新以确保字段位置正确
    await nextTick()
    // 强制更新组件以重新计算字段位置
    placedFields.value = [...placedFields.value]
  } catch (error) {
    console.error('预览失败:', error)
    ElMessage.error('预览失败，请重试')
  }
}

// 监听预览对话框关闭
watch(previewVisible, async (newVal) => {
  if (newVal) {
    // 对话框打开时，等待渲染完成后更新字段位置
    await nextTick()
    await nextTick()
    placedFields.value = [...placedFields.value]
  } else {
    // 清理预览数据
    const previewPdfUrl = sessionStorage.getItem('certificatePreviewUrl')
    if (previewPdfUrl) {
      URL.revokeObjectURL(previewPdfUrl)
      sessionStorage.removeItem('certificatePreviewUrl')
    }
    
    // 清理预览canvas
    const context = previewCanvas.value?.getContext('2d')
    if (context) {
      context.clearRect(0, 0, previewCanvas.value.width, previewCanvas.value.height)
    }
  }
})

// 组件加载时从本地存储加载数据
onMounted(async () => {
  try {
    const savedTemplate = localStorage.getItem('certificateTemplate')
    if (savedTemplate) {
      const templateData = JSON.parse(savedTemplate)
      placedFields.value = templateData.fields || []
      
      console.log('[加载] 从本地存储加载模板数据:', templateData)
      
      // 如果有PDF数据，转换并加载
      if (templateData.pdfBase64) {
        pdfData.value = base64ToArrayBuffer(templateData.pdfBase64)
        pdfUrl.value = URL.createObjectURL(new Blob([pdfData.value], { type: 'application/pdf' }))
        
        // 等待DOM更新后再渲染PDF
        await nextTick()
        await renderPDF(pdfData.value.slice(0), pdfCanvas.value)
      }
    }
    
    // 添加窗口调整大小事件，确保字段位置正确
    window.addEventListener('resize', handleResize)
    window.addEventListener('keydown', handleKeydown)
    
    // 添加提示信息
    ElMessage({
      message: '使用方向键可以微调字段位置：\n' +
               '- 普通方向键：正常调整\n' +
               '- Shift + 方向键：精细调整\n' +
               '- Ctrl + 方向键：大幅调整',
      type: 'info',
      duration: 2000
    })
  } catch (error) {
    console.error('加载保存的模板失败:', error)
  }
})

// 组件卸载时移除事件监听器
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
  window.removeEventListener('keydown', handleKeydown)
})

// 处理窗口大小变化
const handleResize = async () => {
  if (previewVisible.value) {
    // 重新渲染预览
    await nextTick()
    await renderPDF(pdfData.value.slice(0), previewCanvas.value)
    // 等待渲染完成后更新字段位置
    await nextTick()
    placedFields.value = [...placedFields.value]
  }
}

// 新增：获取编辑区canvas的宽高
const getEditCanvasSize = () => {
  const canvas = pdfCanvas.value
  return canvas ? { width: canvas.width, height: canvas.height } : { width: 1, height: 1 }
}

// 新增：编辑区渲染字段时用百分比定位
const getEditFieldStyle = (field) => {
  const canvas = pdfCanvas.value
  const rect = canvas ? canvas.getBoundingClientRect() : { width: 1, height: 1 }
  const left = (field.percentX ?? 0.5) * rect.width
  const top = (field.percentY ?? 0.5) * rect.height
  console.log('[字段渲染] label:', field.label, 'percentX:', field.percentX, 'percentY:', field.percentY, 'left:', left, 'top:', top, 'fontSize:', field.fontSize, 'color:', field.color, 'fontWeight:', field.fontWeight)
  return {
    position: 'absolute',
    transform: 'translate(-50%, -50%)',
    left: left + 'px',
    top: top + 'px',
    fontSize: (field.fontSize || 16) + 'px',
    color: field.color || '#000000',
    fontWeight: field.fontWeight || 'normal',
    cursor: 'move',
    background: 'rgba(255,255,255,0.7)',
    padding: '4px 8px',
    borderRadius: '4px',
    border: '1px solid #dcdfe6',
    whiteSpace: 'nowrap',
    textAlign: 'center',
    fontFamily: 'Helvetica, Arial, sans-serif'
  }
}

// 新增：预览时字段位置也用百分比定位
const getPreviewFieldStyle = (field) => {
  const canvas = previewCanvas.value
  const rect = canvas ? canvas.getBoundingClientRect() : { width: 1, height: 1 }
  
  // 使用PDF原始尺寸和canvas尺寸的比例来计算实际位置
  const scaleX = rect.width / pdfOriginalWidth.value
  const scaleY = rect.height / pdfOriginalHeight.value
  
  const left = (field.percentX ?? 0.5) * rect.width
  const top = (field.percentY ?? 0.5) * rect.height
  
  console.log('[预览样式] 计算字段位置:', field.label, 
    '位置百分比:', field.percentX, field.percentY, 
    '容器尺寸:', rect.width, rect.height,
    'PDF原始尺寸:', pdfOriginalWidth.value, pdfOriginalHeight.value,
    '缩放比例:', scaleX, scaleY,
    '计算位置:', left, top)
  
  return {
    position: 'absolute',
    transform: 'translate(-50%, -50%)',
    left: left + 'px',
    top: top + 'px',
    fontSize: ((field.fontSize || 16) * Math.min(scaleX, scaleY)) + 'px',
    color: field.color || '#000000',
    fontWeight: field.fontWeight || 'normal',
    background: 'rgba(255,255,255,0.8)',
    padding: '4px 8px',
    borderRadius: '4px',
    border: '1px solid #dcdfe6',
    whiteSpace: 'nowrap',
    textAlign: 'center',
    fontFamily: 'Helvetica, Arial, sans-serif',
    zIndex: 1
  }
}

// 键盘微调事件
const handleKeydown = (e) => {
  if (selectedFieldIndex.value === null) return
  const field = placedFields.value[selectedFieldIndex.value]
  if (!field) return

  // 根据修饰键选择步长
  let step = BASE_NUDGE_STEP
  if (e.shiftKey) {
    step = FINE_NUDGE_STEP // Shift键按下时使用精细步长
  } else if (e.ctrlKey) {
    step = LARGE_NUDGE_STEP // Ctrl键按下时使用大步长
  }

  let changed = false
  if (e.key === 'ArrowUp') {
    field.percentY = Math.max(0, field.percentY - step)
    changed = true
  } else if (e.key === 'ArrowDown') {
    field.percentY = Math.min(1, field.percentY + step)
    changed = true
  } else if (e.key === 'ArrowLeft') {
    field.percentX = Math.max(0, field.percentX - step)
    changed = true
  } else if (e.key === 'ArrowRight') {
    field.percentX = Math.min(1, field.percentX + step)
    changed = true
  }

  if (changed) {
    // 更新字段位置
    placedFields.value = [...placedFields.value]
    console.log('[键盘微调] label:', field.label, 
                'percentX:', field.percentX.toFixed(4), 
                'percentY:', field.percentY.toFixed(4),
                'step:', step,
                'modifiers:', e.shiftKey ? 'Shift' : e.ctrlKey ? 'Ctrl' : 'None')
    e.preventDefault()
  }
}
</script>

<style scoped>
.certificate-template {
  padding: 20px;
  height: calc(100vh - 100px);
  background-color: #f5f7fa;
}

.template-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.header-left {
  display: flex;
  align-items: center;
  gap: 20px;
}

.header-left .el-button {
  margin-right: 0;
}

.header-left h2 {
  margin: 0;
}

.template-name-input {
  width: 300px;
}

.template-content {
  display: grid;
  grid-template-columns: 250px 1fr 250px;
  gap: 20px;
  height: calc(100% - 60px);
}

.tools-panel, .properties-panel {
  background: #fff;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  height: fit-content;
}

.field-list {
  margin-top: 10px;
}

.field-item {
  padding: 10px;
  margin-bottom: 10px;
  background: #f5f7fa;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  cursor: move;
  transition: all 0.3s;
}

.field-item:hover {
  background: #ecf5ff;
  border-color: #409eff;
}

.template-upload {
  margin-top: 20px;
}

.design-area {
  background: #fff;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
  min-height: 600px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.template-background {
  width: 100%;
  height: 100%;
  min-height: 600px;
  position: relative;
}

.pdf-canvas {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  object-fit: contain;
}

.empty-background {
  width: 100%;
  height: 100%;
  min-height: 600px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #909399;
  font-size: 16px;
  background-color: #fff;
}

.placed-field {
  position: absolute;
  padding: 4px 8px;
  background: rgba(255, 255, 255, 0.8);
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  cursor: move;
  user-select: none;
  z-index: 1;
  font-family: Helvetica, Arial, sans-serif;
}

.placed-field:hover {
  border-color: #409eff;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

.property-item {
  margin-bottom: 15px;
}

.property-item label {
  display: block;
  margin-bottom: 5px;
  color: #606266;
}

.preview-container {
  width: 100%;
  height: 600px;
  position: relative;
  margin: 0 auto;
  background-color: #fff;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
}

.preview-background {
  width: 100%;
  height: 100%;
  position: relative;
  background-color: #f5f7fa;
  display: flex;
  justify-content: center;
  align-items: center;
}

.pdf-canvas {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  object-fit: contain;
}

.preview-field {
  position: absolute;
  padding: 4px 8px;
  background: rgba(255, 255, 255, 0.8);
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  white-space: nowrap;
  z-index: 1;
  font-family: Helvetica, Arial, sans-serif;
  pointer-events: none;
}

:deep(.el-upload-dragger) {
  width: 100%;
}

:deep(.el-upload__tip) {
  margin-top: 8px;
  color: #909399;
}

:deep(.el-dialog__body) {
  padding: 20px;
  background-color: #f5f7fa;
}

.shortcut-tips {
  position: fixed;
  bottom: 20px;
  right: 5px;
  width: 280px;
  background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  border-radius: 8px;
  z-index: 1000;
}

.tips-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: bold;
  color: #409eff;
}

.tips-content {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.tip-item {
  display: flex;
  align-items: center;
  gap: 12px;
}

.key {
  background: #f5f7fa;
  padding: 4px 8px;
  border-radius: 4px;
  font-family: monospace;
  color: #409eff;
  font-weight: bold;
  min-width: 100px;
  text-align: center;
}

.description {
  color: #606266;
}
</style> 
